package com.yusvn.scm.goods.fenhuo.service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.jfinal.kit.Kv;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.yusvn.scm.common.BaseService;
import com.yusvn.scm.common.constant.Const;
import com.yusvn.scm.common.kit.MyKit;
import com.yusvn.scm.common.kit.RetKit;


/**
 * 批发分货 - 期货
 * @author liugz
 *
 */
public class ScmFenhuoPifaQihuoService extends BaseService {
	
	//表1 导出
	public Page<Record> exportHh(Kv kv) {
		kv.set("cid", getCid()); //账套id
		Page<Record> recPage = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoKhdh", kv).paginate(getPage(kv), getLimit(kv));
		return recPage;
	}
	
	//	表4 导出
	public List<Record> exportFhjgmx(Kv kv) {
		kv.set("cid", getCid()); //账套id
		List<Record> recPage = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.exportFhjgmx", kv).find(); //.paginate(getPage(kv), getLimit(kv));
		return recPage;
	}
	
	// 批发期货分货 - 查询客户订货数据
	public Page<Record> pifaQihuoHh(Kv kv) throws Exception {
		//账套id
		String cid = getCid(); 
		kv.set("cid", cid);
		
		//获取发货仓（多品牌不同发货总仓）
		Record fhckRec = Db.use(Const.SCMDB).template("scmBase.fhck2", kv).findFirst();
		String zc = fhckRec.getStr("pz1"); //总仓
		String[] ypcArr = fhckRec.getStr("pz2").replace("，", ",").split(","); //样品仓
		String[] mdcArr = fhckRec.getStr("pz3").replace("，", ",").split(","); //门店仓
		kv.set("scm_zc", zc); //总仓
		kv.set("scm_ypc", ypcArr); //样品仓
		kv.set("scm_mdc", mdcArr); //门店仓
		
		// 删除客户订货临时表scm_fenhuo_khdh的数据
		Db.use(Const.SCMDB).delete("delete from scm_fenhuo_khdh where cid=? and userid=? ", getCid(), kv.getStr("userid"));
		// 删除客户订货明细临时表scm_fenhuo_khdhmx的数据
		Db.use(Const.SCMDB).delete("delete from scm_fenhuo_khdhmx where cid=? and userid=? ", getCid(), kv.getStr("userid"));
		
		//删除24小时前的分货数据 
		Db.use(Const.SCMDB).templateByString("delete from scm_fenhuo_fhjgmx where cid=#(cid) and userid=#(userid) and createtime<(sysdate-24/24) ", kv).delete();
		
		// 查询数据新增到客户订货临时表scm_fenhuo_khdh
		Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoKhdhAdd", kv).update();
		
		// 查询结果到页面
		Page<Record> recPage = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoKhdh", kv).paginate(getPage(kv), getLimit(kv));
		
		// 查询数据新增到客户订货明细临时表scm_fenhuo_khdhmx
		List<String> spList = recPage.getList().stream().map(r -> r.getStr("spid")).distinct().collect(Collectors.toList());
		if(spList.size()>0) {
			kv.set("spid", spList);
			Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoKhdhmxAdd", kv).update();
		}
		
		return recPage;
	}
		
	// 批发期货分货 - 查询客户订货明细（临时表中）
	public Page<Record> pifaQihuoKh(Kv kv) {
		kv.set("cid", getCid()); //账套id
		// 客户订货明细临时表中，查询结果到页面
		Page<Record> recPage = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoKh", kv).paginate(getPage(kv), getLimit(kv));
		return recPage;
	}
		
	// 批发期货分货 - 3单款分货结果-展示到界面
	public Page<Record> pifaQihuoJg(Kv kv) {
		kv.set("cid", getCid()); //账套id
		Page<Record> recPage = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJg", kv).paginate(getPage(kv), getLimit(kv));
		return recPage;
	}
		
	// 批发期货分货 - 4结果 按客户汇总
	public Page<Record> pifaQihuoJgKhhz(Kv kv) {
		kv.set("cid", getCid()); //账套id
		
		//删除24小时前的分货数据 
		Db.use(Const.SCMDB).templateByString("delete from scm_fenhuo_fhjgmx where cid=#(cid) and userid=#(userid) and createtime<(sysdate-24/24) ", kv).delete();
		
		Page<Record> recPage = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJgKhhz", kv).paginate(getPage(kv), getLimit(kv));
		return recPage;
	}
	
	// 批发期货分货 - 5结果 某客户分货明细
	public Page<Record> pifaQihuoJgKhmx(Kv kv) {
		kv.set("cid", getCid()); //账套id
		Page<Record> recPage = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJgKhmx", kv).paginate(getPage(kv), getLimit(kv));
		return recPage;
	}
		
	//查询表1商品更新行颜色 分货状态fhzt
	public List<Record> pifaQihuoJgGxspys(Kv kv) {
		kv.set("cid", getCid()); //账套id
		
		//统计当前分货结果（用于更新表1颜色）
		List<Record> recList = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJgGxspys", kv).find();
		return recList;
	}
	
	// 批发期货分货 - 查询条件 - 撤销分货(批量)
	public RetKit pifaQihuoCxczCxfh(Kv kv) {
		kv.set("cid", getCid()); //账套id
		List<Record> spArr = JSON.parseArray(kv.getStr("ks"), Record.class); //(JSONArray) kv.get("spid")	
		//删除分货结果临时表
		Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJsCxfhJg", kv).update();
		
		return RetKit.ok("撤销分货完成"+ spArr.size());
	}

	/**
	 * 批发期货分货 - 查询条件 - 一键分货(批量)
	 * @param kv
	 * @return
	 */
	public RetKit pifaQihuoCxczYjfh(Kv kv) throws Exception {
		kv.set("cid", getCid()); //账套id
		
		// 勾选的款
		List<Record> spList = MyKit.jsonStrToList(kv.getStr("ks")); //JSONArray.parseArray(kv.getStr("ks"), Record.class);
		//System.out.println(" spList:"+spList);
		
		//一、设置通用查询参数
		//获取发货仓（多品牌不同发货总仓）
		Record fhckRec = Db.use(Const.SCMDB).template("scmBase.fhck2", kv).findFirst();
		
		//查询设置的所有码段规则
		List<Record> gzcmRecList = Db.use(Const.SCMDB).find("select * from scm_maduan "
				+ "order by types, sizegroup, sort_number, length(sizes) desc, sizes, id");  //order by types, sizegroup, sort_number, length(sizes) desc, sizes, id
		
		//获取是否匹配尺码规则 scm_ppcmgz
		String ppcmgz = Db.use(Const.SCMDB).queryStr("select pz1 from scm_pzfh where bh='scm_ppcmgz' ");
		kv.set("ppcmgz", ppcmgz);

		//获取是否匹配尺码规则 scm_ppcmgz
		String sfbqm = Db.use(Const.SCMDB).queryStr("select pz1 from scm_pzfh where bh='scm_sfbqm' ");
		kv.set("sfbqm", sfbqm);
		
		//二、循环调用预分货计算方法
		for(Record sp : spList) {
			kv.set("spid", sp.get("spid"));
			kv.set("ysid", sp.get("ysid"));
			//System.out.println(" sp:"+sp);
			
			//先删除分货结果中的数据
			Db.use(Const.SCMDB).delete("delete from scm_fenhuo_fhjgmx where cid=? and userid=? and spid=? and ysid=? ",
					kv.get("cid"), kv.get("userid"), kv.get("spid"), kv.get("ysid") );
			
			//调用 预分货计算 方法
			jsfh(kv, fhckRec, gzcmRecList); 
		}
		
		return RetKit.ok("一键分货完成 "+spList.size());
	}
	
//	// 重算分货 TODO
//	public RetKit pifaQihuoCsfh(Kv kv) {
//		return RetKit.ok();
//	}
	
	/**
	 * 匹配尺码规则
	 * （库存尺码和设置设置的码段规则进行匹配）
	 * @param kccmList
	 * @param crcmList
	 * @return false不匹配，true匹配
	 */
	public boolean jsMaduan(List<String> kccmList, List<String> crcmList, List<Record> gzcmRecList, Record spRec) {
		//System.out.println("采入尺码："+crcmList+"库存尺码："+kccmList);
		//库存尺码数量
		int kccmCnt = kccmList.size();
		if(kccmCnt<=0) {
			return false;
		}
		
		int ppkcCnt = 0; //库存尺码与码段规则尺码能匹配上的数量
		int ppcrCnt = 0; //采购入库尺码与码段规则尺码能匹配上的数量
		//循环所有码段规则
		for(Record gzcmRec : gzcmRecList) {
//			//判断尺码组，如果码段规则中的尺码组字段值和商品档案中的尺码字段值相同，才进行后面的匹配 TODO
//			if(!spRec.getStr("cmd").equals(gzcmRec.getStr("sizegroup").trim()) ) {
//				continue;
//			}
			
			//将码段规则的尺码字符串以英文逗号分割成数组
			String[] gzcmArr = gzcmRec.getStr("sizes").replace("，", ",").split(",");
			
			for(String gzcm : gzcmArr) {
				//将库存尺码与码段规则尺码进行匹配
				for(String kccm : kccmList) {
					if(gzcm.trim().equals(kccm.trim())) {
						ppkcCnt = ppkcCnt +1;
					}
				}
				
				//将采购入库尺码与码段规则尺码进行匹配
				for(String crcm : crcmList) {
					if(gzcm.trim().equals(crcm.trim())) {
						ppcrCnt = ppcrCnt +1;
					}
				}
			}
			//System.out.println("需尺码匹配"+" ppkcCnt:"+ppkcCnt+ " ppcrCnt:"+ppcrCnt+ " kccmList:"+kccmList + " crcmList:"+crcmList + " gzcmArr:"+JSON.toJSONString(gzcmArr));
			
			//库存尺码与码段规则尺码匹配； 或者采购入库尺码与码段规则尺码匹配数量=码段规则尺码中的到货码个数，则匹配成功
			if( (ppkcCnt==gzcmArr.length) || (ppcrCnt==gzcmRec.getInt("qty")) ) {
				//System.out.println("尺码匹配"+" ppkcCnt:"+ppkcCnt+ " ppcrCnt:"+ppcrCnt+ " kccmList:"+kccmList + " crcmList:"+crcmList + " gzcmArr:"+JSON.toJSONString(gzcmArr));
				return true;
			}
			ppkcCnt = 0;
			ppcrCnt = 0;
		}
		
		return false;
	}

	// 清除散码（分货结果中的零散尺码）（不能清除补齐码，数量改为0、并加列标记） 
	public boolean jsQcsm(List<String> fhjgcmList, List<String> crcmList, List<Record> gzcmRecList, Record spRec) {
		//System.out.println("采入尺码："+crcmList+"库存尺码："+kccmList);
		//库存尺码数量
		int kccmCnt = fhjgcmList.size();
		if(kccmCnt<=0) {
			return false;
		}
		
		int ppkcCnt = 0; //库存尺码与码段规则尺码能匹配上的数量
		int ppcrCnt = 0; //采购入库尺码与码段规则尺码能匹配上的数量
		//循环所有码段规则
		for(Record gzcmRec : gzcmRecList) {
//			//判断尺码组，如果码段规则中的尺码组字段值和商品档案中的尺码字段值相同，才进行后面的匹配 TODO
//			if(!spRec.getStr("cmd").equals(gzcmRec.getStr("sizegroup").trim()) ) {
//				continue;
//			}
			
			//将码段规则的尺码字符串以英文逗号分割成数组
			String[] gzcmArr = gzcmRec.getStr("sizes").replace("，", ",").split(",");
			
			for(String gzcm : gzcmArr) {
				//将库存尺码与码段规则尺码进行匹配
				for(String kccm : fhjgcmList) {
					if(gzcm.trim().equals(kccm.trim())) {
						ppkcCnt = ppkcCnt +1;
					}
				}
				
				//将采购入库尺码与码段规则尺码进行匹配
				for(String crcm : crcmList) {
					if(gzcm.trim().equals(crcm.trim())) {
						ppcrCnt = ppcrCnt +1;
					}
				}
			}
			//System.out.println("需尺码匹配"+" ppkcCnt:"+ppkcCnt+ " ppcrCnt:"+ppcrCnt+ " kccmList:"+kccmList + " crcmList:"+crcmList + " gzcmArr:"+JSON.toJSONString(gzcmArr));
			
			//库存尺码与码段规则尺码匹配； //或者采购入库尺码与码段规则尺码匹配数量=码段规则尺码中的到货码个数，则匹配成功
			if( (ppkcCnt==gzcmArr.length) ) {
				//System.out.println("尺码匹配"+" ppkcCnt:"+ppkcCnt+ " ppcrCnt:"+ppcrCnt+ " fhjgcmList:"+fhjgcmList + " crcmList:"+crcmList + " gzcmArr:"+JSON.toJSONString(gzcmArr));
				return true;
			}
			ppkcCnt = 0;
			ppcrCnt = 0;
		}
		
		return false;
	}

	
	/**
	 * 将分货结果批量插入数据库
	 * @param kv
	 * @param fhjgList
	 * @return
	 */
	public RetKit addFhjg(Kv kv, List<Record> fhjgList) {
		if(fhjgList.size()>0) {
			Object[][] paras = new Object[fhjgList.size()][15];
			for(int i=0; i<fhjgList.size(); i++) {
				paras[i][0] = getCid(); //cid;
				paras[i][1] = fhjgList.get(i).get("khid");
				paras[i][2] = fhjgList.get(i).get("ckid");
				paras[i][3] = fhjgList.get(i).get("qyid");
				paras[i][4] = fhjgList.get(i).get("skuid");
				paras[i][5] = fhjgList.get(i).get("spid");
				paras[i][6] = fhjgList.get(i).get("ysid");
				paras[i][7] = fhjgList.get(i).get("cmid");
				paras[i][8] = fhjgList.get(i).get("bcfhsl");
				paras[i][9] = fhjgList.get(i).get("dprice");
				paras[i][10] = fhjgList.get(i).get("fprice");
				paras[i][11] = kv.get("userid");
				paras[i][12] = fhjgList.get(i).get("remark");
				paras[i][13] = fhjgList.get(i).get("fhckid");
				paras[i][14] = fhjgList.get(i).get("lx");
			}
			
			Db.use(Const.SCMDB).batch("insert into scm_fenhuo_fhjgmx(id, cid, khid, ckid, qyid,   skuid, spid, ysid, cmid, bcfhsl,   dprice, fprice, userid, remark, fhckid,   lx) " + 
					"	values(GET_SEQ('scm_fenhuo_fhjgmx'), ?, ?, ?, ?,   ?, ?, ?, ?, ?,   ?, ?, ?, ?, ?,  ?) ", paras, 1000);
			
		}
		
		return RetKit.ok();
	}
	
	
	/**
	 * 表1 计算分货
	 * 需求：某款色采购入库尺码数符合码段规则才发货； 先补齐码； 再取出总部仓库存数量和客户订货数据，按4个区域客户订货由高到低交替分货； 再删除零散的分货数据（补齐码不能删除）
	 */
	public RetKit jsfh(Kv kv, Record fhckRec, List<Record> gzcmRecList) {
		//一、取数
		//账套id
		String cid = getCid(); 
		kv.set("cid", getCid());
		
		String zc = fhckRec.getStr("pz1"); //总仓
		String[] ypcArr = fhckRec.getStr("pz2").replace("，", ",").split(","); //样品仓
		String[] mdcArr = fhckRec.getStr("pz3").replace("，", ",").split(","); //门店仓
		kv.set("scm_zc", zc); //总仓
		kv.set("scm_ypc", ypcArr); //样品仓
		kv.set("scm_mdc", mdcArr); //门店仓
		
		//判断当前款色是否满足清样
		Integer qyCnt = Db.use(Const.SCMDB).queryInt("select count(*) as cnt from scm_fenhuo_khdh "
				+ "where qybl>=(select pz1 from scm_pzfh where bh='scm_xsd_qybl') "
				+ "and cid=? and userid=? and spid=? and ysid=? ", cid, kv.get("userid"), kv.get("spid"), kv.get("ysid") );
		 
		//总部发货仓库（如果满足清样，则库存需要取门"店仓+样品仓+门店仓"的库存，否则只取总仓的库存）
		List<String> fhckArr = new ArrayList<String>();
		fhckArr.add(fhckRec.getStr("pz1"));
		if(qyCnt!=null && qyCnt>0) {
			for(String ypc : ypcArr) {
				fhckArr.add(ypc);
			}
			for(String mdc : mdcArr) {
				fhckArr.add(mdc);
			}
		}
		kv.set("fhckArr", fhckArr);
		
		//当前商品信息
		Record spRec = Db.use(Const.SCMDB).findFirst("select sp.id as spid, sp.style as spbh, sp.stylename as spmc, sp.dprice as dpj, sp.cmd "
				+ "from defstyle sp where sp.cid=? and sp.id=? ", cid, kv.get("spid"));
				spRec.set("ysid", kv.get("ysid")); //存入当前款色
		
		//获取某款色 总部库存明细
		List<Record> kcList = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJsSpkcsl", kv).find();
		//计算某款色 库存尺码明细
		List<String> kccmList = kcList.parallelStream().map(r->r.getStr("cmmc")).distinct().collect(Collectors.toList());
		
		//获取某款色 采购入库的尺码
		List<String> crcmList = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJsCrcm", kv).query();
		
		//判断某款色 能否分货。匹配码段规则（库存尺码和设置设置的码段规则进行匹配）（先判断参数中设置了开启此校验规则，0表示不开启，其他数字表示开启）
		if(!kv.getStr("ppcmgz").equals("0")) {
			if(jsMaduan(kccmList, crcmList, gzcmRecList, spRec) == false) {
				System.out.println("匹配码段规则不能分货："+spRec);
				return RetKit.fail();
			}
		}

		//获取某款色 所有客户的订货明细 (必须排除 本次分货结果中分货数 避免重复分)
		List<Record> ddmxList = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJsDdmx", kv).find();
		//ddmxList.stream().forEach(System.out::print);
		
		//获取某款色 所有客户的订货排行，用于分货顺序 (必须排除 本次分货结果中分货数 避免重复分) 
		List<Record> dhpxList = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJsDhpx", kv).find();	

		//暂存客户分销价集合（可以不用每次从数据库中查）
		List<Record> fxjRecList = new ArrayList<Record>();
		
		
		//判断当前款色总仓库存是否小于客户订货剩余数，如果小于才能从样品仓调入总仓清样。
		for(String cmmc : kccmList) {
			//获取某尺码总仓的库存数合计
			Integer cmkc = kcList.parallelStream().filter(r->(r.getStr("cmmc").equals(cmmc) && r.getStr("fhcdbh").equals(zc)) )
					.map(r->r.getInt("kcsl")).reduce(0, Integer::sum);
			//获取某尺码客户订货剩余数合计
			Integer cmdh = ddmxList.parallelStream().filter(r->r.getStr("cmmc").equals(cmmc) )
					.map(r->r.getInt("sysl")).reduce(0, Integer::sum);
			//System.out.println("尺码:"+cmmc+" 总仓库存"+cmkc+" 客户订货"+cmdh+" "+spRec);
			
			//去除非总仓的商品尺码库存，避免总仓此尺码库存数满足分货数却从样品仓调货过来分。
			if(cmkc >= cmdh) {
				kcList.removeIf(r -> (r.getStr("cmmc").equals(cmmc) && !r.getStr("fhcdbh").equals(zc)) );
				//System.out.println(kcList);
			}
		}
		
		
		//二、分货计算（正常分货 类型表示lx为1）
		List<Record> fhjgList = jsFhjg(kv, "1", fxjRecList, dhpxList, ddmxList, kcList);
		
		
		//三、清除散码
		//暂存需要删除的客户分货数据
		List<Record> qcfhjgList = new ArrayList<Record>();
		//获取某款色 分货客户
		List<String> fhjgkhList = fhjgList.parallelStream().map(r->r.getStr("khid")).collect(Collectors.toList());
		
		for(String khid : fhjgkhList) {
			//获取某款色 分货客户尺码明细 去重
			List<String> fhjgCmList = fhjgList.parallelStream().filter(r->r.getStr("khid").equals(khid))
					.map(r->r.getStr("cmmc")).distinct().collect(Collectors.toList());
			//获取某款色 符合删除的 客户分货结果
			if(fhjgCmList.size()>0 && jsQcsm(fhjgCmList, crcmList, gzcmRecList, spRec) == false) {
				Record qcRec = new Record();
				qcRec.set("khid", khid);
				qcRec.set("spid", kv.getStr("spid"));
				qcRec.set("ysid", kv.getStr("ysid"));
				qcRec.set("cid", kv.getStr("cid"));
				qcRec.set("userid", kv.getStr("userid"));
				qcfhjgList.add(qcRec);
			}
		}
		qcfhjgList = qcfhjgList.parallelStream().distinct().collect(Collectors.toList()); //去重
		//System.out.println("符合删除的客户分货结果："+qcfhjgList);
		
		//删除分货结果中符合条件的散码
		Iterator<Record> fhjgIterator = fhjgList.iterator(); 
		while(fhjgIterator.hasNext()) {
			Record fhjg = fhjgIterator.next();
			for(Record qcfhjg : qcfhjgList) {
				if(fhjg.getStr("lx").equals("1")  //正常分货才删除，补齐码不删除
						&& fhjg.getStr("khid").equals(qcfhjg.getStr("khid"))
						&& fhjg.getStr("spid").equals(qcfhjg.getStr("spid"))
						&& fhjg.getStr("ysid").equals(qcfhjg.getStr("ysid"))
						&& fhjg.getStr("cid").equals(qcfhjg.getStr("cid"))
						&& fhjg.getStr("userid").equals(qcfhjg.getStr("userid")) ) {
					fhjgIterator.remove();
				}
			}
		}
		
		
		//四、将分货结果批量写入数据库分货结果临时表中
		addFhjg(kv, fhjgList);
		
		
		//五、补齐码
		//获取所有客户订货未发完的尺码，然后先将分货剩余的库存分给这些需补齐的客户。
		//判断是否开启了补齐码
		if(!kv.getStr("sfbqm").equals("0")) {
			jsBqm(kv, fxjRecList, dhpxList); //调用补齐码方法
		}
		
		return RetKit.ok();
	}
	
	/**
	 * 补齐码<br>
	 * 结果先暂存到集合中
	 * 客户之前分货未分到的尺码优先补齐，再去正常分货<br>
	 * 统计某款商品客户定了几个尺码，已经发了几个尺码。<br>
	 * 缺少的尺码是一次补齐所有数量，还是补齐数量1？先补给谁？<br>
	 * @param kv
	 * @param fxjRecList 暂存分销价集合
	 * @param fhjgList 暂存分货结果集合
	 * @return
	 */
	public RetKit jsBqm(Kv kv, List<Record> fxjRecList, List<Record> dhpxList) {
		//System.out.println(" 开始补齐码");
		//一、取数
		//获取某款色 所有客户的订货明细 (排除分货结果表中已分的数量) 用于补齐码，必须有完整的订货尺码个数，发货尺码个数
		List<Record> ddmxList = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJsDdmx2", kv).find();
		//计算所有订货的客户
		List<String> ddkhList = ddmxList.parallelStream().map(r->r.getStr("khid")).distinct().collect(Collectors.toList());
		
		//某款色 总部库存明细
		List<Record> kcList = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJsSpkcsl", kv).find();
				
		//二、计算需补齐码的客户订货明细
		List<Record> xbqmmxList = new ArrayList<Record>(); //需补齐码集合
		
		for(String ddkh : ddkhList) {
			//获取某客户订发明细
			List<Record> cmdfList = ddmxList.parallelStream().filter(r->r.getStr("khid").equals(ddkh)).collect(Collectors.toList());

			int dhcmCnt = 0;
			int sycmCnt = 0;
			//统计某客户的订货尺码个数、剩余尺码个数（数量大于0）
			for(Record cmdf : cmdfList) {
				//System.out.println(cmdf);
				if(cmdf.get("dhsl")!=null && cmdf.getInt("dhsl")>0) {
					dhcmCnt++;
				}
				if(cmdf.get("sysl")!=null && cmdf.getInt("sysl")>0) {
					sycmCnt++;
				}
			}
			//System.out.println("订货尺码个数："+dhcmCnt+"剩余尺码个数："+sycmCnt+" "+ddkh);
			
			//某客户如果剩余尺码个数大于0、且小于订货尺码个数，则判定为需补齐尺码。 
			if(sycmCnt>0 && sycmCnt<dhcmCnt) {
				//System.out.println("需要补齐尺码。");
				//然后再次循环某客户订货尺码明细，将需要补齐的尺码加入到补齐码集合中。
				for(Record cmdf : cmdfList) {
					if(cmdf.get("dhsl")!=null && cmdf.getInt("dhsl")>0 
							&& (null!=cmdf.get("sysl") && cmdf.getInt("sysl")>0) ) {
							xbqmmxList.add(cmdf); //将数据添加到需补齐码集合中
							//System.out.println(cmdf);
					}
				}
			}
			
		}
		
		
		//三、补齐码计算 （分货类型lx为2）
		List<Record> fhjgList = jsFhjg(kv, "2", fxjRecList, dhpxList, xbqmmxList, kcList);

		//四、将分货结果批量插入数据库
		addFhjg(kv, fhjgList);
		
		return RetKit.ok();
	}
	
	/**
	 * 计算分货 （正常分货、补齐码 暂时通用）
	 * @param kv
	 * @param fxjRecList
	 * @param dhpxList
	 * @param ddmxList
	 * @param kcList
	 * @return
	 */
	public List<Record> jsFhjg(Kv kv, String fhlx, List<Record> fxjRecList, List<Record> dhpxList, List<Record> ddmxList, List<Record> kcList) {
		//暂存分货结果集合
		List<Record> fhjgList = new ArrayList<Record>();
		
		//统计当前款色码最大库存
		int kskc = 0;
		OptionalInt kskcOpt = kcList.parallelStream().mapToInt(r -> r.getInt("kcsl")).max();
		if(kskcOpt != null && kskcOpt.isPresent()) {
			kskc = kskcOpt.getAsInt();
		}
		
		spFor:
		for(int i=0; i<=kskc; i++) {
			//每一轮分货，实际分给客户的次数（用于后面判断是否需要继续下轮分货）
			int fhcs = 0;
			
			//循环当前款色客户的订货排行  （按每个区域客户订货数交叉排序，比如先分每个区域第1名、再分每个区域第2名...）
			for(Record dhpx : dhpxList) {
				
				//循环当前款色当前客户订货明细(到尺码)
				Iterator<Record> ddmxIterator = ddmxList.iterator();
				while(ddmxIterator.hasNext()) {
					Record ddmx = ddmxIterator.next();
					
					//非当前排序客户，则先不进行分货
					if(!dhpx.getStr("khid").equals(ddmx.getStr("khid"))) {
						continue;
					}
					
					//移除已经分完的客户订货明细
					if(ddmx.getInt("sysl")<=0) {
						ddmxIterator.remove();
						continue;
					}
					
					//循环当前款色库存(到尺码)
					Iterator<Record> kcIterator = kcList.iterator(); 
					while(kcIterator.hasNext()) {
						Record kc = kcIterator.next();
						
						//移除已经分完的库存
						if(kc.getInt("kcsl") <= 0) {
							kcIterator.remove();
							continue;
						}
					
						//订单明细和库存匹配，则分货给客户，每轮数量减1
						if(kc.getStr("cmid").equals(ddmx.getStr("cmid")) 
							&& kc.getInt("kcsl") > 0 //判断库存剩余数量是否大于0
							&& ddmx.getInt("sysl") > 0 //判断订单剩余数量是否大于0 
							) {
							//库存-1，订货剩余数-1
							kc.set("kcsl", kc.getInt("kcsl")-1);
							ddmx.set("sysl", ddmx.getInt("sysl")-1);
							
							//新增分货数据到集合
							Record rec = new Record();
							rec.set("cid", getCid());
							rec.set("userid", kv.getStr("userid"));
							rec.set("khid", ddmx.getStr("khid")); //客户id
							rec.set("qyid", StrKit.isBlank(ddmx.getStr("qyid")) ? null : ddmx.getStr("qyid"));
							rec.set("ckid", ddmx.getStr("ckid")); //客户仓库id
							rec.set("skuid", ddmx.getStr("skuid"));
							rec.set("spid", ddmx.getStr("spid"));
							rec.set("ysid", ddmx.getStr("ysid"));
							rec.set("cmid", ddmx.getStr("cmid"));
							rec.set("cmmc", ddmx.getStr("cmmc"));
							rec.set("fhckid", kc.get("fhckid")); //发货仓库id fhckid
							rec.set("bcfhsl", 1);
							rec.set("dprice", 0); //标准价 //ddmx.getStr("dprice")
							
							//获取分销价（先取临时集合中是否有值，没值再去数据库中取，减少连库次数）
							double fprice = 0;
							Optional<Double> fxjOpt = fxjRecList.parallelStream().filter(r-> r.getStr("khid").equals(ddmx.getStr("khid")) )
									.map(r->r.getDouble("fxj")).findFirst();
							if(fxjOpt != null && fxjOpt.isPresent()) {
								fprice = fxjOpt.get();
							}else {
								fprice = Db.use(Const.SCMDB).templateByString("select getfprice2(#(khid), #(spid), to_char(sysdate,'yyyymmdd'), 1, 1) "
										+ "from defbuyer where id=#(khid)", Kv.create().set("spid", ddmx.getStr("spid")).set("khid", ddmx.getStr("khid")) ).queryDouble();
								Record fxjRec = new Record();
								fxjRec.set("khid", ddmx.getStr("khid"));
								fxjRec.set("fxj", fprice);
								fxjRecList.add(fxjRec);
							}
							rec.set("fprice", fprice); //销售价  getfprice2(#(khid), #(spid), to_char(sysdate,'yyyymmdd'), 1, 1) ；   GetFPriceAdj(p_BuyerId, p_StyleId, p_billdate, p_saleType, p_retType)
							
							rec.set("remark", null);
							rec.set("lx", fhlx);  //分货类型（1正常分货,2补齐码）
							
							//保存分货结果到集合
							fhjgList.add(rec);
							//System.out.println(" 发货仓:"+kc.get("fhckid") +" 客户:"+ddmx.getStr("ckid") +" 商品:"+ddmx.getStr("spid") +" 颜色:"+ddmx.getStr("ysid") +" 尺码:"+ddmx.getStr("cmid") + " 数量:1");
							
							fhcs = fhcs + 1;
						}
					}
					
				}
					
			}
	
			//如果当前这一轮分货，没有分掉一件库存，则表示没有订单与库存匹配了，则不进行下轮分货
			if(fhcs<=0) {
				break spFor;
			}
		}
		
		return fhjgList;
	}
	
	
	// 批发期货分货 - 单款分货结果-表4撤销此客户
	public RetKit pifaQihuoJgCxckh(Kv kv) {
		kv.set("cid", getCid()); //账套id
		
		//删除分货结果 明细
		int cnt = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJgCxckhmx", kv).update();
		//删除分货结果 整单
		Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJgCxckh", kv).update();
		if(cnt>=0) {
			//调用重算方法，重新计算撤销客户已分的商品，将其分给其他客户 TODO
			//pifaQihuoPCs(kv);
			
			return RetKit.ok("删除此客户成功 "+cnt);
		}
		try {
			
		} catch (Exception e) {
			System.out.println(e);
			return RetKit.fail("删除此客户失败。"); //e.getMessage()
		}
				
		return RetKit.fail("删除此客户失败");
	}
	
	
	// 批发期货分货 - 单款分货结果-表3撤销此款
	public RetKit pifaQihuoJgCxck(Kv kv) {
		kv.set("cid", getCid()); //账套id
		try {
			int cnt = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJgCxck", kv).update();
			if(cnt>=0) {
				//调用重算方法，重新计算撤销的商品，将其分给其他客户 TODO
				//pifaQihuoCsfh(kv);
				
				return RetKit.ok("删除此款客户分货成功 "+cnt);
			}
		} catch (Exception e) {
			System.out.println(e);
			return RetKit.fail("删除此款客户分货失败。"); //e.getMessage()
		}
				
		return RetKit.fail("删除此款客户分货失败");
	}
	
	
	// 批发期货分货 - 单款分货结果-表3修改数据
	public RetKit pifaQihuoJgXgsj(Kv kv) {
		kv.set("cid", getCid()); //账套id
		try {
			//先查询判断是否存在，再修改?  TODO
			Record fhRec = Db.use(Const.SCMDB).templateByString("SELECT * FROM scm_fenhuo_fhjgmx where cid=#(cid) and userid=#(userid) "
					+ "and khid='#(khid)' and ckid='#(ckid)' and fhckid='#(fhckid)' and spid='#(spid)' and ysid='#(ysid)' and cmid='#(cmid)' ", kv).findFirst();
			fhRec.set("cmid", kv.get("cmid"));
			fhRec.set("skuid", kv.get("skuid"));
			kv.set("id", fhRec.get("id"));
			
			//删除
			Db.use(Const.SCMDB).templateByString("delete from scm_fenhuo_fhjgmx where cid=#(cid) and userid=#(userid) "
					+ "and khid='#(khid)' and ckid='#(ckid)' and fhckid='#(fhckid)' and spid='#(spid)' and ysid='#(ysid)' "
					+ "and cmid='#(cmid)' and id<>'#(id)' ", kv).delete();
			
			//修改
			int cnt = Db.use(Const.SCMDB).template("scmFenhuoPifaQihuo.pifaQihuoJgXgsj", kv).update();
			if(cnt>=0) {
				//调用重算方法，重新计算撤销的商品，将其分给其他客户 TODO
				//pifaQihuoCsfh(kv);
				
				return RetKit.ok("修改成功 "+cnt);
			}
		} catch (Exception e) {
			System.out.println(e);
			return RetKit.fail("修改失败。"); //e.getMessage()
		}
				
		return RetKit.fail("修改失败");
	}
	
	//  批发期货分货 - 表5获取整单备注
	public RetKit pifaQihuoJgHqbz(Kv kv) {
		kv.set("cid", getCid()); //账套id
		Record zdbz = Db.use(Const.SCMDB).templateByString("select zdbz from scm_fenhuo_fhjg "
				+ "where cid=#(cid) and userid=#(userid) and khid=#(khid) ", kv).findFirst();
		return RetKit.ok("获取成功").setData(zdbz);
	}
	
	//  批发期货分货 - 表5保存整单备注
	public RetKit pifaQihuoJgBcbz(Kv kv) {
		kv.set("cid", getCid()); //账套id
		kv.set("zdbz",kv.getStr("zdbz").replace("'", " "));
		//查询是否存在，存在就修改，不存在就新增
		int cnt = Db.use(Const.SCMDB).templateByString("select count(*) as cnt from scm_fenhuo_fhjg "
				+ "where cid=#(cid) and userid=#(userid) and khid=#(khid) ", kv).queryInt();
		int cnt2 = 0;
		if(cnt>0) {
			cnt2 = Db.use(Const.SCMDB).templateByString("update scm_fenhuo_fhjg set zdbz='#(zdbz)' "
					+ "where cid=#(cid) and userid=#(userid) and khid=#(khid) ", kv).update();
		}else {
			cnt2 = Db.use(Const.SCMDB).templateByString("insert into scm_fenhuo_fhjg(id, cid, userid, khid, zdbz) "
					+ "values(GET_SEQ('scm_fenhuo_fhjg'), #(cid), #(userid), #(khid), '#(zdbz)') ", kv).update();
		}
		
		if(cnt2>0) {
			return RetKit.ok("保存成功");
		}
		return RetKit.fail("保存失败");
	}
	
	// 批发期货分货 - 查询条件 - 生成销售单(批量)
	public RetKit pifaQihuoCxczScxxd(Kv kv) {
		kv.set("cid", getCid()); //账套id
		
		//查询设置的默认生成单据用户ID 815
		String czybh = Db.queryStr("select config_value1 from scm_config where config_code='scm_xsd_yhbh' ");
		//String czyid = Db.use(Const.SCMDB).queryStr("select id from sysuser where cid=#(cid) and username=? ", czybh);
		
		//查询设置的默认发货仓ID 468
		String fhckbh = Db.queryStr("select config_value1 from scm_config where config_code='scm_xsd_fhdc' ");
		//String fhckid = Db.use(Const.SCMDB).queryStr("select * from defstore where cid=#(cid) and store=? ", fhckbh);
		try {
			String cid=getCid();
			String userid=kv.getStr("userid");

			//先删除之前临时表用户勾选的id
			Db.use(Const.SCMDB).update("delete from scm_base_ids where cid=? and userid=? and lx='fh_scdj' ", cid, userid);
			
			//存入用户勾选的id到临时表
			JSONArray idsArr = JSON.parseArray(kv.getStr("khid"));
			Object[][] paras = new Object[idsArr.size()][3];
			for(int i=0;i<idsArr.size();i++) {
				paras[i][0] = idsArr.get(i);
				paras[i][1] = cid;
				paras[i][2] = userid;
			}
			//Thread.sleep(1000*5); // 休眠5秒
			Db.use(Const.SCMDB).batch("insert into scm_base_ids(id, cid, lx, userid) values(?, ?, 'fh_scdj', ?)", paras, 100);
			
			//调用存储过程生成销售单及调拨单（传设置的 账套id\分货用户id\发货仓编号\生成单据用户编号）
			Db.use(Const.SCMDB).update("CALL proc_scm_scxsd(?,?,?,?) ", getCid(), userid, fhckbh, czybh);
			
			//删除临时表用户勾选的id
			Db.use(Const.SCMDB).update("delete from scm_base_ids where cid=? and userid=? and lx='fh_scdj' ", cid, userid);
			
		} catch (Exception e) {
			e.printStackTrace();
			return RetKit.fail("生成单据失败:"+e.getMessage() );
		}
		return RetKit.ok("生成单据成功");
	}

	
	/**
	    --调用函数更新分销价 GetFPrice、GetFPrice2、
	    update BUSsaledt set fprice=GetFPrice(vr.dest,skuid,vr.billdate,v_distype,0,vr.modifyid) where masterid=p_id;
        
        -- 销售价调整单中的销售折扣saletype、退货折扣rettype，(1期货) 用户id暂时设置为空p_userid
		-- GetFPrice2(p_BuyerId in number, p_StyleId in number, p_billdate in number, p_saleType in number, p_retType in number, p_userid in number default null)
		
		select getfprice2(2282, 123694, 20201208, 1, 1, null) 
		from defbuyer where id=2282;
	 */
	
}
